import java.util.StringTokenizer;


public abstract class ShipObject extends MovingObject
{
	protected double direction; // direction in radians
								// note that +direction is CLOCKWISE rotation, since the +y axis
								// points toward the bottom of the screen
	//-Stationary Sound;
    //-Moving Sound
    
    protected static final double ACCEL_SPEED = 200; // pixels per second^2, can be changed by subclasses
    protected static final double TURN_SPEED = Math.PI; // radians per second^2, can be changed
    protected static final double MAX_SPEED = 250; // soft maximum speed
    
    // shooting parameters 
    // the timing stuff only makes sense if it is a multiple of 20 (1000/FRAME_RATE))
    protected static final int BURST_SHOTS = 4; // shots per burst
    protected static final int BURST_TIME = 500; // ms between last shot and start of next burst
    protected static final int SHOT_TIME = 100; // ms between shots in the same burst
    
    
    protected int accelerating; // -1, 0, 1 depending on direction of acceleration
    protected int turning; // -1, 0, or 1
    protected boolean shooting;
    
    protected int burstCount; // shots left in the current burst
    protected int burstCooldown; // ms before next burst is ready
    protected int shotCooldown; // ms before next shot can happen
    
    
    
    public ShipObject(int x, int y)
    {
    	super(x,y);
    	accelerating = 0;
    	turning = 0;
    	shooting = false;
    	
    	burstCount = BURST_SHOTS;
    	shotCooldown = 0;
    	burstCooldown = 0;
    }
    
    public ShipObject()
	{
		super();
	}
    
    public double getDirection()
    {
    	return direction;
    }
    
    protected void loadState(StringTokenizer strtok) throws NumberFormatException
	{
		super.loadState(strtok);
		direction = Double.parseDouble(strtok.nextToken());
		accelerating = Integer.parseInt(strtok.nextToken());
		turning = Integer.parseInt(strtok.nextToken());
		shooting = Boolean.parseBoolean(strtok.nextToken());
		burstCount = Integer.parseInt(strtok.nextToken());
		burstCooldown = Integer.parseInt(strtok.nextToken());
		shotCooldown = Integer.parseInt(strtok.nextToken());
	}
	protected String saveState()
	{
		return super.saveState() + String.format("%f %d %d %s %d %d %d ",
				direction, accelerating, turning, shooting, burstCount, burstCooldown, shotCooldown);
	}
    
    // Overrides move() from MovingObject
    public void move()
    {
    	// update direction, and wrap it to [-pi, pi]
    	direction += turning * TURN_SPEED/FRAME_RATE;
    	direction %= Math.PI*2;
    	if(direction < -Math.PI)
    		direction += 2*Math.PI;
    	else if(direction > Math.PI)
    		direction -= 2*Math.PI;
    	
    	if(accelerating == 1)
    	{
    		vx += ACCEL_SPEED/FRAME_RATE * Math.cos(direction);
    		vy += ACCEL_SPEED/FRAME_RATE * Math.sin(direction);
    		
    		
    		// slightly reduce high speed to maintain a speed that is close enough
    		// to the maximum
    		if(getSpeed() > MAX_SPEED)
    		{
    			vx *= 0.98;
    			vy *= 0.98;
    		}
    	}
    	if(accelerating == -1)
    	{
    		vx -= sign(vx) * ACCEL_SPEED/FRAME_RATE;
    		vy -= sign(vy) * ACCEL_SPEED/FRAME_RATE;
    
    		// if speed is slower than two ticks of acceleration, just zero it
    		// the threshold here needs to be large enough to prevent bouncing
    		// back and forth around 0
    		if(getSpeed() < 2*ACCEL_SPEED/FRAME_RATE)
    		{
    			vx = vy = 0;
    		}
    	}
    	
    	
    	
    	// ships are all affected by gravity
    	if(AsteroidsGame.game.planet != null)
    	{
    		double dir = -AsteroidsGame.game.planet.direction(this); // negative for attraction
    		double mag = AsteroidsGame.game.planet.forceMag(this);
    		vx -= mag*Math.cos(dir);
    		vy += mag*Math.sin(dir);
    	}
    	
    	// update shot timers
    	shotCooldown -= 1000/FRAME_RATE;
    	burstCooldown -= 1000/FRAME_RATE;
    	
    	// shoot if we can
    	if(shooting && shotCooldown <= 0 && burstCount > 0)
    	{
			AsteroidsGame.game.addObject(new Bullet((int)x, (int)y, this));
			//AsteroidsGame.soundManager.play(AsteroidsGame.laser);
			burstCount--;
			shotCooldown = SHOT_TIME; // time between shots
			burstCooldown = BURST_TIME; // start timer for next burst
    	}
    	// if burst timer has expired, reset shot count once
    	if(burstCount < BURST_SHOTS && burstCooldown <= 0)
    	{
    		burstCount = BURST_SHOTS;
    	}
    	
    	
    	// this needs to be last, so that the moves on this tick take into account changes
    	super.move(); 
    }
}
